#include <stdint.h>
#include <string>
#include <stdio.h>

#include <ace/xcomponent/native_interface_xcomponent.h>
#include <hilog/log.h>

#include "plugin_manager.h"
#include "../common/common.h"

PluginManager PluginManager::m_pluginManager;

PluginManager::~PluginManager()
{
    for (auto iter = m_nativeXComponentMap.begin(); iter != m_nativeXComponentMap.end(); ++iter) {
        if (nullptr != iter->second) {
            delete iter->second;
            iter->second = nullptr;
        }
    }
    m_nativeXComponentMap.clear();

    for (auto iter = m_pluginRenderMap.begin(); iter != m_pluginRenderMap.end(); ++iter) {
        if (nullptr != iter->second) {
            delete iter->second;
            iter->second = nullptr;
        }
    }
    m_pluginRenderMap.clear();
}

/**
 * 从 ArkTS 调用中获取一个上下文值，并根据该值注册生命周期管理功能
 * @param env NAPI 环境，表示当前的执行上下文
 * @param info 回调信息，包含调用该函数的上下文数据
 * @return 一个 JavaScript 对象，其将被用于生命周期相关的注册
 */
napi_value PluginManager::GetContext(napi_env env, napi_callback_info info)
{
    // 空指针检测
    if ((nullptr == env) || (nullptr == info)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetContext env or info is null");
        return nullptr;
    }

    // 一次性获取所有传入的原始参数
    size_t argCnt = 1;
    napi_value args[1] = { nullptr }; // 用于存储ArkTS侧传入的参数，类型统一为napi_value（这里预计要收到1个参数，所以数组容量为1）
    if (napi_ok != napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetContext napi_get_cb_info failed");
    }

    // Debug信息：ArkTS侧传入的参数数量不为1时打印错误信息
    if (1 != argCnt) {
        napi_throw_type_error(env, NULL, "Wrong number of arguments");
        return nullptr;
    }

    // 取出args[0]的类型并将其赋值给变量valuetype
    napi_valuetype valuetype;
    napi_typeof(env, args[0], &valuetype);
    if (napi_number != valuetype) {
        napi_throw_type_error(env, NULL, "Wrong type of arguments");
        return nullptr;
    }

    // 将原始参数取出为int类型
    int64_t value;
    if (napi_ok != napi_get_value_int64(env, args[0], &value)) {
        napi_throw_type_error(env, NULL, "napi_get_value_int64 failed");
        return nullptr;
    }

    /** 创建一个新的 JavaScript 对象，并将其用于生命周期管理的注册 */
    // 声明变量
    napi_value exports;
    // 创建对象
    napi_create_object(env, &exports);
    // 注册生命周期
    // 根据传入值的不同将不同的生命周期函数注册到新建的export对象上
    RegisterLifecycle(env, exports, value);

    // 将对象返回
    return exports;
}

/**
 * 根据不同的value值注册不同的生命周期到export对象上
 */
void PluginManager::RegisterLifecycle(napi_env env, napi_value exports, int64_t value)
{
    switch (value) {
        // 如果要注册的是App的生命周期
        case APP_LIFECYCLE: {
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginManager", "RegisterLifecycle: APP_LIFECYCLE");
            napi_property_descriptor desc[] = {
                {"onCreate", nullptr, PluginManager::NapiOnCreate, nullptr, nullptr, nullptr, napi_default, nullptr},
                {"onShow", nullptr, PluginManager::NapiOnShow, nullptr, nullptr, nullptr, napi_default, nullptr},
                {"onHide", nullptr, PluginManager::NapiOnHide, nullptr, nullptr, nullptr, napi_default, nullptr},
                {"onDestroy", nullptr, PluginManager::NapiOnDestroy, nullptr, nullptr, nullptr, napi_default, nullptr}
            };
            // 将4个生命周期函数挂载到export对象上
            napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
            break;
        }
        // 如果要注册的是页面的生命周期
        case PAGE_LIFECYCLE: {
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginManager", "RegisterLifecycle: PAGE_LIFECYCLE");
            napi_property_descriptor desc[] = {
                {"aboutToAppear", nullptr, PluginManager::NapiToAppear, nullptr, nullptr, nullptr, napi_default, nullptr},
                {"aboutToDisappear", nullptr, PluginManager::NapiToDisappear, nullptr, nullptr, nullptr, napi_default, nullptr},
                {"onPageShow", nullptr, PluginManager::NapiOnPageShow, nullptr, nullptr, nullptr, napi_default, nullptr},
                {"onPageHide", nullptr, PluginManager::NapiOnPageHide, nullptr, nullptr, nullptr, napi_default, nullptr}
            };
            // 将4个生命周期函数挂载到export对象上
            napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
            break;
        }
        default: {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager",
                "RegisterLifecycle: wrong type of value");
            break;
        }
    }
}

void PluginManager::Export(napi_env env, napi_value exports)
{
    // 空指针检测
    if ((nullptr == env) || (nullptr == exports)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: env or exports is null");
        return;
    }

    // napi_get_named_property 用于从一个 JavaScript 对象中获取指定名称的属性
    // 从 exports 对象中获取名为 OH_NATIVE_XCOMPONENT_OBJ 的属性，并将其存储在 exportInstance 中(现在还是原始类型)
    napi_value exportInstance = nullptr;
    if (napi_ok != napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: napi_get_named_property fail");
        return;
    }

    // 从原始类型中解包出精确类型：从 exportInstance 对象中提取底层的 C++ 指针，并将其赋值给 nativeXComponent
    OH_NativeXComponent *nativeXComponent = nullptr;
    napi_status res = napi_unwrap(env, exportInstance, reinterpret_cast<void **>(&nativeXComponent));
    if (napi_ok != res) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: napi_unwrap fail 结果：%{public}d", res);
        return;
    }

    // 声明一个字符数组 idStr，用于存储组件 ID。数组长度为 OH_XCOMPONENT_ID_LEN_MAX + 1，以便容纳 ID 字符串及其结束符 '\0'
    char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' };
    // 声明一个 uint64_t 类型的变量 idSize，用于存储 ID 字符串的大小。初始值设置为 OH_XCOMPONENT_ID_LEN_MAX + 1，表示可以存储的最大字符数
    uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    // 从 nativeXComponent 中获取组件 ID，并将其存储在 idStr 中，同时更新 idSize 以反映实际写入的字符数。
    if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager",
            "Export: OH_NativeXComponent_GetXComponentId fail");
        return;
    }

    // 从字符数组 idStr 创建一个 std::string 类型的对象 id
    std::string id(idStr);
    auto pluginManagerInstance = PluginManager::GetInstance();
    if ((nullptr != pluginManagerInstance) && (nullptr != nativeXComponent)) {
        // 将组件 ID 和 nativeXComponent 关联起来
        m_nativeXComponentMap[id] = nativeXComponent;
        // 获取到该id对应的Render
        auto render = pluginManagerInstance->GetRender(id);
        // 为nativeXComponent注册surface生命周期和触摸事件回调：PluginRender::m_callback
        OH_NativeXComponent_RegisterCallback(nativeXComponent, &PluginRender::m_callback);
        if (nullptr != render) {
            OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "render->Export执行");
            render->Export(env, exports);
        }
    }
}

PluginRender *PluginManager::GetRender(std::string &id)
{
    // 检查RenderMap中是否有id，没有id的话走if流程
    if (m_pluginRenderMap.find(id) == m_pluginRenderMap.end()) {
        PluginRender *instance = PluginRender::GetInstance(id);
        // 给指定id新建一个Render实例
        m_pluginRenderMap[id] = instance;
        return instance;
    }

    return m_pluginRenderMap[id];
}

napi_value PluginManager::NapiOnCreate(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnCreate");
    return nullptr;
}

napi_value PluginManager::NapiOnShow(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnShow");
    return nullptr;
}

napi_value PluginManager::NapiOnHide(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnHide");
    return nullptr;
}

napi_value PluginManager::NapiOnDestroy(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnDestroy");
    return nullptr;
}

napi_value PluginManager::NapiToAppear(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiToAppear");
    return nullptr;
}

napi_value PluginManager::NapiToDisappear(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiToDisappear");
    return nullptr;
}

napi_value PluginManager::NapiOnPageShow(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnPageShow");
    return nullptr;
}

napi_value PluginManager::NapiOnPageHide(napi_env env, napi_callback_info info)
{
    OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnPageHide");
    return nullptr;
}